<template>
  <h3>订单详情</h3>
  <div class="order-train">
    <span class="order-train-main">{{ trainTicket.date }}</span>
    &nbsp;
    <span class="order-train-main">{{ trainTicket.trainCode }}</span>
    次&nbsp;
    <span class="order-train-main">{{ trainTicket.start }}</span>
    站
    <span class="order-train-main">({{ trainTicket.startTime }})</span>
    &nbsp;
    <span class="order-train-main">——</span>
    &nbsp;
    <span class="order-train-main">{{ trainTicket.end }}</span>
    站
    <span class="order-train-main">({{ trainTicket.endTime }})</span>
    &nbsp;

    <div class="order-train-ticket">
      <span v-for="item in seatTypes" :key="item.type">
        <span>{{ item.desc }}</span>
        ：
        <span class="order-train-ticket-main">{{ item.price }}￥</span>
        &nbsp;
        <span class="order-train-ticket-main">{{ item.count }}</span>
        &nbsp;张票&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      </span>
    </div>
  </div>
  <a-divider></a-divider>
  <b>勾选要购票的乘客：</b>
  &nbsp;
  <a-checkbox-group v-model:value="passengerChecks" :options="passengerOptions" />
  <div class="order-tickets">
    <a-row v-if="tickets.length > 0" class="order-tickets-header">
      <a-col :span="2">乘客</a-col>
      <a-col :span="6">身份证</a-col>
      <a-col :span="4">票种</a-col>
      <a-col :span="4">座位类型</a-col>
    </a-row>
    <a-row v-for="ticket in tickets" :key="ticket.passengerId" class="order-tickets-row">
      <a-col :span="2">{{ ticket.passengerName }}</a-col>
      <a-col :span="6">{{ ticket.passengerIdCard }}</a-col>
      <a-col :span="4">
        <a-select v-model:value="ticket.passengerType" style="width: 100%">
          <a-select-option v-for="item in PASSENGER_TYPE_ARRAY" :key="item.code" :value="item.code">
            {{ item.description }}
          </a-select-option>
        </a-select>
      </a-col>
      <a-col :span="4">
        <a-select v-model:value="ticket.seatTypeCode" style="width: 100%">
          <a-select-option v-for="item in seatTypes" :key="item.code" :value="item.code">
            {{ item.desc }}
          </a-select-option>
        </a-select>
      </a-col>
    </a-row>
  </div>
  <div v-if="tickets.length > 0">
    <a-button type="primary" size="large" @click="finishCheckPassenger">提交订单</a-button>
  </div>
  <!-- 订单确认 -->
  <a-modal
    v-model:visible="visible"
    title="请核对以下信息"
    style="top: 50px; width: 800px"
    ok-text="确认"
    cancel-text="取消"
    @ok="showFirstImageCodeModal"
  >
    <div class="order-tickets">
      <a-row v-if="tickets.length > 0" class="order-tickets-header">
        <a-col :span="3">乘客</a-col>
        <a-col :span="15">身份证</a-col>
        <a-col :span="3">票种</a-col>
        <a-col :span="3">座位类型</a-col>
      </a-row>
      <a-row v-for="ticket in tickets" :key="ticket.passengerId" class="order-tickets-row">
        <a-col :span="3">{{ ticket.passengerName }}</a-col>
        <a-col :span="15">{{ ticket.passengerIdCard }}</a-col>
        <a-col :span="3">
          <span v-for="item in PASSENGER_TYPE_ARRAY" :key="item.code">
            <span v-if="item.code === ticket.passengerType">
              {{ item.description }}
            </span>
          </span>
        </a-col>
        <a-col :span="3">
          <span v-for="item in seatTypes" :key="item.code">
            <span v-if="item.code === ticket.seatTypeCode">
              {{ item.desc }}
            </span>
          </span>
        </a-col>
      </a-row>
      <br />
      <div v-if="chooseSeatType === 0" style="color: red">
        您购买的车票不支持选座
        <div>12306规则：只有全部是一等座或全部是二等座才支持选座</div>
        <div>12306规则：余票小于一定数量时，不允许选座（本项目以20为例）</div>
      </div>
      <div v-else style="text-align: center">
        <a-switch
          v-for="item in SEAT_COL_ARRAY"
          :key="item.code"
          v-model:checked="chooseSeatObj[item.code + '1']"
          class="choose-seat-item"
          :checked-children="item.description"
          :un-checked-children="item.description"
        />
        <div v-if="tickets.length > 1">
          <a-switch
            v-for="item in SEAT_COL_ARRAY"
            :key="item.code"
            v-model:checked="chooseSeatObj[item.code + '2']"
            class="choose-seat-item"
            :checked-children="item.description"
            :un-checked-children="item.description"
          />
        </div>
        <div style="color: #999999">提示：您可以选择{{ tickets.length }}个座位</div>
      </div>
      <br />
      <div style="color: red">
        体验排队购票，加入多人一起排队购票：
        <a-input-number v-model:value="lineNumber" :min="0" :max="20" />
      </div>
      <br />
      最终购票：{{ tickets }} 最终选座：{{ chooseSeatObj }}
    </div>
  </a-modal>
  <!-- 第一层验证码 纯前端 -->
  <a-modal
    v-model:visible="firstImageCodeModalVisible"
    :title="null"
    :footer="null"
    :closable="false"
    style="top: 50px; width: 400px"
  >
    <p style="text-align: center; font-weight: bold; font-size: 18px">
      使用纯前端验证码削弱瞬时高峰
      <br />
      减小后端验证码接口的压力
    </p>
    <p>
      <a-input v-model:value="firstImageCodeTarget" placeholder="验证码">
        <template #suffix>{{ firstImageCodeSourceA }} + {{ firstImageCodeSourceB }}</template>
      </a-input>
    </p>
    <a-button type="danger" block @click="validFirstImageCode">提交验证码</a-button>
  </a-modal>
  <!-- 第二层验证码 后端 -->
  <a-modal
    v-model:visible="imageCodeModalVisible"
    :title="null"
    :footer="null"
    :closable="false"
    style="top: 50px; width: 400px"
  >
    <p style="text-align: center; font-weight: bold; font-size: 18px">
      使用服务端验证码削弱瞬时高峰
      <br />
      防止机器人刷票
    </p>
    <p>
      <a-input v-model:value="imageCode" placeholder="图片验证码">
        <template #suffix>
          <img v-show="!!imageCodeSrc" :src="imageCodeSrc" alt="验证码" @click="loadImageCode()" />
        </template>
      </a-input>
    </p>
    <a-button type="danger" block @click="handleOk">输入验证码后开始购票</a-button>
  </a-modal>
  <a-modal
    v-model:visible="lineModalVisible"
    title="排队购票"
    :footer="null"
    :mask-closable="false"
    :closable="false"
    style="top: 50px; width: 400px"
  >
    <div class="book-line">
      <div v-show="confirmOrderLineCount < 0">
        <loading-outlined />
        系统正在处理中...
      </div>
      <div v-show="confirmOrderLineCount >= 0">
        <loading-outlined />
        您前面还有{{ confirmOrderLineCount }}位用户在购票，排队中，请稍候
      </div>
    </div>
    <br />
    <a-button type="danger" @click="onCancelOrder">取消购票</a-button>
  </a-modal>
</template>
<script setup lang="ts">
import { enumApi } from '@/api/enum';
import { passengerApi } from '@/api/passenger';
import { message } from 'ant-design-vue';
import { computed, onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { SEAT_TYPE } from '@/utils/enum';
import { confirmOrderApi } from '@/api/order';

const route = useRoute();
// 解密
const trainTicket = computed(() => {
  const encodedData = route.query.ticket;
  return JSON.parse(decodeURIComponent(encodedData as any));
});

const seatTypes = ref<any[]>([]);
onMounted(async () => {
  // 构造一个参数结构
  for (const key in SEAT_TYPE) {
    const lowerKey = key.toLowerCase();
    if (trainTicket.value[lowerKey] >= 0) {
      seatTypes.value.push({
        type: lowerKey,
        code: SEAT_TYPE[key].code,
        desc: SEAT_TYPE[key].desc,
        count: trainTicket.value[lowerKey],
        price: trainTicket.value[lowerKey + 'Price'],
      });
    }
  }
  console.log('本车次提供的座位：', seatTypes.value);
});

// 字典
//#region
const PASSENGER_TYPE_ARRAY = ref<any[]>([]);
onMounted(async () => {
  const { data } = await enumApi.getEnumList('passenger_type');
  PASSENGER_TYPE_ARRAY.value = data;
  console.log('所有乘客数据', data);
});
//#endregion

// 乘客 + 选票
//#region
const passengers = ref([]);
const passengerOptions = ref([]);
const passengerChecks = ref([]);
const tickets = ref<any[]>([]);
onMounted(() => {
  getPassengerAllList();
});
watch(
  () => passengerChecks.value,
  (newVal, oldVal) => {
    console.log('勾选乘客发生变化', newVal, oldVal);
    // 每次有变化时，把购票列表清空，重新构造列表
    tickets.value = [];
    passengerChecks.value.forEach((item: any) => {
      console.log('item', item);
      tickets.value.push({
        passengerId: item.id,
        passengerType: item.type,
        seatTypeCode: seatTypes.value[0].code,
        passengerName: item.name,
        passengerIdCard: item.idCard,
      });
    });
  },
  { immediate: true }
);
const getPassengerAllList = async (): Promise<void> => {
  const { data } = await passengerApi.getPassengerAllList();
  passengers.value = data || [];
  passengerOptions.value = data.map((item: any) => {
    return {
      label: item.name,
      value: item,
    };
  });
};
//#endregion

// 是否支持选座
// 0：不支持选座；1：选一等座；2：选二等座
const chooseSeatType = ref(0);
const SEAT_COL_ENUM = ref<any[]>([]);
const lineNumber = ref(5);
// seat_col
onMounted(async () => {
  const { data } = await enumApi.getEnumList2('seat_col');
  SEAT_COL_ENUM.value = data || [];
});
// 根据选择的座位类型，计算出对应的列，比如要选的是一等座，就筛选出ACDF，要选的是二等座，就筛选出ABCDF
const SEAT_COL_ARRAY = computed(() => {
  return SEAT_COL_ENUM.value.filter((item: any) => item.type === chooseSeatType.value);
});
// 选择的座位
// {
//   A1: false, C1: true，D1: false, F1: false，
//   A2: false, C2: false，D2: true, F2: false
// }
const chooseSeatObj = ref<any>({});
watch(
  () => SEAT_COL_ARRAY.value,
  () => {
    // 先清空，再重新赋值
    chooseSeatObj.value = {};
    for (let i = 1; i <= 2; i++) {
      SEAT_COL_ARRAY.value.forEach((item: any) => {
        chooseSeatObj.value[item.code + i] = false;
      });
    }
    console.log('初始化两排座位，都是未选中：', chooseSeatObj.value);
  },
  { immediate: true }
);

// 提交订单
//#region
const visible = ref(false);
// 打开提交订单模态框
const finishCheckPassenger = (): void => {
  console.log('提交订单', tickets.value);
  // 1. 一次最多只能购买五张车票;
  if (tickets.value.length > 5) {
    message.error('最多只能购买5张车票');
    return;
  }
  // 2. 校验余票是否充足
  let seatTypesTemp = JSON.parse(JSON.stringify(seatTypes.value)); // 拷贝临时遍历判断库存
  for (let i = 0; i < tickets.value.length; i++) {
    let ticket = tickets.value[i]; // 当前票
    for (let j = 0; j < seatTypesTemp.length; j++) {
      let seatType = seatTypesTemp[j]; // 当前座位
      if (seatType.code === ticket.seatTypeCode) {
        if (seatType.count <= 0) {
          message.error(`当前${seatType.desc}座位已无余票`);
          return;
        }
        seatType.count--;
      }
    }
  }
  console.log('前端余票校验通过');
  // 3. 判断是否支持选座，只有纯一等座和纯二等座支持选座
  // 先筛选出购票列表中的所有座位类型，比如四张表：[1, 1, 2, 2]
  let ticketSeatTypeCodes = [];
  for (let i = 0; i < tickets.value.length; i++) {
    let ticket = tickets.value[i];
    ticketSeatTypeCodes.push(ticket.seatTypeCode);
  }
  // 为购票列表中的所有座位类型去重：[1, 2]
  const ticketSeatTypeCodesSet = Array.from(new Set(ticketSeatTypeCodes));
  console.log('选好的座位类型：', ticketSeatTypeCodesSet);
  if (ticketSeatTypeCodesSet.length !== 1) {
    console.log('选了多种座位，不支持选座');
    chooseSeatType.value = 0;
  } else {
    // ticketSeatTypeCodesSet.length === 1，即只选择了一种座位（不是一个座位，是一种座位）
    if (ticketSeatTypeCodesSet[0] === SEAT_TYPE.YDZ.code) {
      console.log('一等座选座');
      chooseSeatType.value = SEAT_TYPE.YDZ.code;
    } else if (ticketSeatTypeCodesSet[0] === SEAT_TYPE.EDZ.code) {
      console.log('二等座选座');
      chooseSeatType.value = SEAT_TYPE.EDZ.code;
    } else {
      console.log('不是一等座或二等座，不支持选座');
      chooseSeatType.value = 0;
    }

    // 余票小于20张时，不允许选座，否则选座成功率不高，影响出票
    if (chooseSeatType.value !== 0) {
      for (let i = 0; i < seatTypes.value.length; i++) {
        let seatType = seatTypes.value[i];
        // 找到同类型座位
        if (ticketSeatTypeCodesSet[0] === seatType.code) {
          // 判断余票，小于20张就不支持选座
          if (seatType.count < 20) {
            console.log('余票小于20张就不支持选座');
            chooseSeatType.value = 0;
            break;
          }
        }
      }
    }
  }

  // 弹出确认界面
  visible.value = true;
};

/**
 * 加载第一层验证码
 */
/* ------------------- 第一层验证码 --------------------- */
const firstImageCodeSourceA = ref();
const firstImageCodeSourceB = ref();
const firstImageCodeTarget = ref();
const firstImageCodeModalVisible = ref();
const showFirstImageCodeModal = (): void => {
  loadFirstImageCode();
  firstImageCodeModalVisible.value = true;
};

const loadFirstImageCode = (): void => {
  // 获取1~10的数：Math.floor(Math.random()*10 + 1)
  firstImageCodeSourceA.value = Math.floor(Math.random() * 10 + 1) + 10;
  firstImageCodeSourceB.value = Math.floor(Math.random() * 10 + 1) + 20;
};
/**
 * 校验第一层验证码
 */
const validFirstImageCode = (): void => {
  if (
    parseInt(firstImageCodeTarget.value) ===
    parseInt(firstImageCodeSourceA.value + firstImageCodeSourceB.value)
  ) {
    // 第一层验证通过
    firstImageCodeModalVisible.value = false;
    showImageCodeModal();
  } else {
    message.error('验证码错误');
  }
};

/**
 * 显示第二层验证码
 */
const imageCodeToken = ref();
const imageCodeSrc = ref();
const imageCode = ref();
const imageCodeModalVisible = ref(false);
/**
 * 加载图形验证码
 */
const showImageCodeModal = (): void => {
  loadImageCode();
  imageCodeModalVisible.value = true;
};
const loadImageCode = (): void => {
  imageCodeToken.value = crypto.randomUUID().substring(0, 8);
  imageCodeSrc.value =
    import.meta.env.VITE_APP_BACKEND_HOST + '/business/kaptcha/image-code/' + imageCodeToken.value;
};

/* ------------------- 定时查询订单状态 --------------------- */
// 确认订单后定时查询
let queryLineCountInterval: any;
// 定时查询订单结果/排队数量
const queryLineCount = (): void => {
  confirmOrderLineCount.value = -1;
  queryLineCountInterval = setInterval(async function () {
    const res = await confirmOrderApi.queryQueue(confirmOrderId.value);
    console.log('res', res);
    if (res.success) {
      let result = res.data;
      switch (result) {
        case -1:
          message.success('购票成功！');
          lineModalVisible.value = false;
          clearInterval(queryLineCountInterval);
          break;
        case -2:
          message.error('购票失败！');
          lineModalVisible.value = false;
          clearInterval(queryLineCountInterval);
          break;
        case -3:
          message.error('抱歉，没票了！');
          lineModalVisible.value = false;
          clearInterval(queryLineCountInterval);
          break;
        default:
          confirmOrderLineCount.value = result;
      }
    } else {
      message.error(res.message);
    }
  }, 500);
};

// 提交订单
const lineModalVisible = ref(false);
const confirmOrderLineCount = ref(-1);
const confirmOrderId = ref();
const handleOk = async (): Promise<void> => {
  if (!imageCode.value) {
    message.error('验证码不能为空');
    return;
  }
  console.log('选好的座位：', chooseSeatObj.value);
  // 设置每张票的座位
  // 先清空购票列表的座位，有可能之前选了并设置座位了，但选座数不对被拦截了，又重新选一遍
  for (let i = 0; i < tickets.value.length; i++) {
    tickets.value[i].seat = null;
  }
  let i = -1;
  // 要么不选座位，要么所选座位应该等于购票数，即i === (tickets.value.length - 1)
  for (let key in chooseSeatObj.value) {
    if (chooseSeatObj.value[key]) {
      i++;
      if (i > tickets.value.length - 1) {
        message.error('所选座位数大于购票数');
        return;
      }
      tickets.value[i].seat = key;
    }
  }
  if (i > -1 && i < tickets.value.length - 1) {
    message.error('所选座位数小于购票数');
    return;
  }

  console.log('最终购票：', tickets.value);

  // 调用确认订单的接口(将最后的购票信息传递给后端)
  try {
    const { data } = await confirmOrderApi.doConfirm({
      dailyTrainTicketId: trainTicket.value.id,
      trainCode: trainTicket.value.trainCode,
      date: trainTicket.value.date,
      start: trainTicket.value.start,
      end: trainTicket.value.end,
      tickets: tickets.value,
      // 增加验证码的key和值
      imageCodeToken: imageCodeToken.value,
      imageCode: imageCode.value,
      // 增加体验排队的人数
      lineNumber: lineNumber.value,
    });
    // message.success('下单成功');
    confirmOrderId.value = data;
    console.log('data', data);
    visible.value = false;
    imageCodeModalVisible.value = false;
    lineModalVisible.value = true;
    queryLineCount();
  } catch (error: any) {
    console.log('error', error.message);
  } finally {
    loadImageCode();
  }
};
/**
 * 取消排队
 */
const onCancelOrder = async (): Promise<void> => {
  const data = await confirmOrderApi.cancelQueue(confirmOrderId.value);
  if (data.success) {
    let result = data.content;
    if (result === 1) {
      message.success('取消成功！');
      // 取消成功时，不用再轮询排队结果
      clearInterval(queryLineCountInterval);
      lineModalVisible.value = false;
    } else {
      message.error('取消失败！');
    }
  } else {
    message.error(data.message);
  }
};
//#endregion
</script>

<style scoped lang="less">
.order-train .order-train-main {
  font-size: 18px;
  font-weight: bold;
}
.order-train .order-train-ticket {
  margin-top: 15px;
}
.order-train .order-train-ticket .order-train-ticket-main {
  color: red;
  font-size: 18px;
}

.order-tickets {
  margin: 10px 0;
}
.order-tickets .ant-col {
  padding: 5px 10px;
}
.order-tickets .order-tickets-header {
  background-color: cornflowerblue;
  border: solid 1px cornflowerblue;
  color: white;
  font-size: 16px;
  padding: 5px 0;
}
.order-tickets .order-tickets-row {
  border: solid 1px cornflowerblue;
  border-top: none;
  vertical-align: middle;
  line-height: 30px;
}

.order-tickets .choose-seat-item {
  margin: 5px 5px;
}
</style>
